#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2019 crane <crane@crane-pc>
#
# Distributed under terms of the MIT license.


'''
NOTE: 这个文件模仿操作系统OS 实现的两种锁, spinlock 和mutex
'''

# ------------------- 使用xchg实现lock_util, release_util效果  ---------------------

def lock_util(lock_entity):
    # to是局部变量
    to = 1

    # xchg理解为cpu指令, 逻辑等价于如下代码顺序执行并且不被打断.
    # NOTE: lock_entity, to = to, lock_entity

    # 如果lock_entity为0, lock_entity == origin, 会导致lock_entity, to = to, lock_entity, 也就是lock_entity = 1, to = 0
    # 否则, 如果lock_entity为1, xchg 会导致to 依旧是1, 没有发生变化.
    xchg lock_entity to

    if to == 0:    # 拿锁成功了, lock_entity被成功设置为了1(如果拿锁没成功, 说明lock_entity已经被别人设置为1)
        return True

    return False

def release_util(lock_entity):
    lock_entity = 0


# ------------------- 以下是OS/操作系统 提供的lock功能 ---------------------
# ------------------- 自旋锁, 一直尝试型 ---------------------
class MySpinLock:
    def __init__(self):
        self.lock_entity = 0

    def lock():
        # 如果lock_util失败, 一直尝试
        while not lock_util(self.lock_entity):
            pass

        return

    def release():
        release_util(self.lock_entity)


# ------------------- Mutex, 如果锁失败, 当前进程/线程加入sleep队列, 直到锁释放, 再唤醒 ---------------------
class MyMutex:
    def __init__(self):
        self.lock_entity = 0

    def lock():
        if lock_util(self.lock_entity):
            # 加锁成功, 返回
            return
        else:
            # 加锁失败, 导致自己进入睡眠/sleep状态
            push_current_process_into_sleep(lock_entity)

    def release():
        release_util(self.lock_entity)
